package com.quectel.business.dms.application.access.accessor.ipg.impl;

import com.google.common.base.Preconditions;
import com.quectel.business.dms.application.ApplicationAccessConf;
import com.quectel.business.dms.application.access.accessor.ipg.AbstractIntelligentParkingGateAccessor;
import com.quectel.business.dms.application.access.accessor.ipg.model.AuthCarCmd;
import com.quectel.business.dms.application.access.accessor.ipg.model.GuardOpenResp;
import com.quectel.business.dms.application.access.basemodel.ApplicationOriginDevice;
import com.quectel.constant.core.car.CarConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.constant.sys.SysConfigKeyConstants;
import com.quectel.core.module.application.dto.ApplicationDto;
import com.quectel.core.module.application.service.ApplicationService;
import com.quectel.core.module.car.dto.CarDto;
import com.quectel.core.module.car.service.CarService;
import com.quectel.core.module.device.dto.DeviceCommandTemplateDto;
import com.quectel.core.module.device.dto.DeviceDto;
import com.quectel.sdk.simulation.SimulationClientBuilder;
import com.quectel.sdk.simulation.basemodel.SimulationDevice;
import com.quectel.sdk.simulation.constant.SimulationConstants;
import com.quectel.sdk.simulation.parkinggate.ParkingGateClient;
import com.quectel.sdk.simulation.parkinggate.model.AuthCarReq;
import com.quectel.sdk.simulation.parkinggate.model.CarInfoResp;
import com.quectel.sys.module.sys.dto.SysTenantDto;
import com.quectel.sys.module.sys.service.SysTenantService;
import com.quectel.util.common.Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 在这里编写说明
 *
 * @author: rananxin
 * @email: ryan.ran@quectel.com
 * @date: 2022-12-13 14:33:00
 */
@Component
@Slf4j
public class SimulationParkingGateAccessorImpl extends AbstractIntelligentParkingGateAccessor {

    @DubboReference
    private CarService carService;
    @DubboReference
    private ApplicationService applicationService;
    @DubboReference
    private SysTenantService sysTenantService;

    /**
     * 模拟车闸平台开闸成功同步返回结果
     * @param applicationId
     * @param deviceUniqueId
     * @return
     */
    @Override
    public GuardOpenResp open(Long applicationId, String deviceUniqueId) {
        ApplicationDto application = applicationService.selectCacheById(applicationId);
        Preconditions.checkNotNull(application);

        try {
            ApplicationAccessConf.TemplateOfSimulationConf conf = ApplicationAccessConf
                    .parseExtStr(ApplicationAccessConf.TemplateOfSimulationConf.class, application.getAccessConf());

            Preconditions.checkNotNull(conf);
            ParkingGateClient parkingGateClient = SimulationClientBuilder.builder()
                    .url(conf.getUrl())
                    .accessKey(conf.getAccessKey())
                    .accessSecret(conf.getAccessSecret())
                    .build(ParkingGateClient.class);

            boolean open = parkingGateClient.open(deviceUniqueId);
            return GuardOpenResp.builder().openResult(open).build();
        } catch (Exception e) {
            log.warn("设备uniqueId {} 开闸异常", deviceUniqueId);
        }
        return GuardOpenResp.builder().build();
    }

    @Override
    public void authCar(AuthCarCmd authCarCmd) {
        List<AuthCarCmd.DeviceInfo> deviceInfoList = authCarCmd.getDeviceInfoList();
        Map<Long, List<AuthCarCmd.DeviceInfo>> deviceGroupByApplicationMap = deviceInfoList.parallelStream()
                .collect(Collectors.groupingBy(AuthCarCmd.DeviceInfo::getApplicationId));
        for (Map.Entry<Long, List<AuthCarCmd.DeviceInfo>> longListEntry : deviceGroupByApplicationMap.entrySet()) {
            ApplicationDto application = applicationService.selectCacheById(longListEntry.getKey());
            SysTenantDto sysTenantDto = sysTenantService.selectById(application.getTenantId());
            if (Objects.isNull(sysTenantDto)) {
                log.warn("Parking gate auth car, tenant is null.");
                continue;
            }

            try {

                ApplicationAccessConf.TemplateOfSimulationConf conf = ApplicationAccessConf
                        .parseExtStr(ApplicationAccessConf.TemplateOfSimulationConf.class, application.getAccessConf());

                Preconditions.checkNotNull(conf);
                ParkingGateClient parkingGateClient = SimulationClientBuilder.builder()
                        .url(conf.getUrl())
                        .accessKey(conf.getAccessKey())
                        .accessSecret(conf.getAccessSecret())
                        .build(ParkingGateClient.class);

                String[] codes = longListEntry.getValue().parallelStream().map(AuthCarCmd.DeviceInfo::getDeviceUniqueId).toArray(String[]::new);
                String innerBaseUrl = sysConfigService.getConfigValueByKey(SysConfigKeyConstants.GATEWAY_INNER_BASE_URL);
                if (StringUtils.isBlank(innerBaseUrl)) {
                    log.warn("Parking gate auth car error, gatewayOuterBaseUrl config is blank.");
                    return ;
                }
                parkingGateClient.auth(AuthCarReq.builder()
                        .type(authCarCmd.getType())
                        .license(authCarCmd.getLicense())
                        .licenseColor(authCarCmd.getLicenseColor())
                        .codes(codes)
                        .deadline(authCarCmd.getDeadline())
                        .payload(authCarCmd.getPayload())
                        .callBackUrl(String.format("%s%ssimulation/eventRcv/authResp/%s", innerBaseUrl
                                , SystemConstants.ApiPath.COLLECT_PATH.getPath(), sysTenantDto.getCode())).build());

            } catch (Exception e) {
                log.warn("车辆授权异常 ", e);
            }
        }
    }

    @Override
    public boolean initApplication(ApplicationDto application) {
        return syncOrRegisterDevices(application, null)
                && subscribeEvents(application);
    }

    @Override
    public boolean syncOrRegisterDevices(ApplicationDto application, List<ApplicationOriginDevice> devices) {
        final Date currentDate = new Date();

        ApplicationAccessConf.TemplateOfSimulationConf conf = ApplicationAccessConf
                .parseExtStr(ApplicationAccessConf.TemplateOfSimulationConf.class, application.getAccessConf());

        try {
            Preconditions.checkNotNull(conf);
            ParkingGateClient parkingGateClient = SimulationClientBuilder.builder()
                    .url(conf.getUrl())
                    .accessKey(conf.getAccessKey())
                    .accessSecret(conf.getAccessSecret())
                    .build(ParkingGateClient.class);

            // 获取车辆
            if (Objects.nonNull(application.getVillageId())) {
                // 未知小区车辆不同步
                List<CarInfoResp> cars = parkingGateClient.cars();
                List<CarDto> carDtos = cars.parallelStream().filter(o -> {
                    CarDto carDto = carService.selectOneByCache(application.getVillageId()
                            , o.getLicense(), CarConstants.LicenseColorEnum.COMMON.getLicenseColor());
                    return Objects.isNull(carDto);
                }).map(o -> {
                    CarDto carDto = new CarDto();
                    carDto.setTenantId(application.getTenantId());
                    carDto.setVillageId(application.getVillageId());
                    carDto.setLicense(o.getLicense());
                    carDto.setCarType(CarConstants.CarTypeEnum.COMMON.getCarType());
                    carDto.setLicenseColor(CarConstants.LicenseColorEnum.COMMON.getLicenseColor());
                    carDto.setOwnerName(o.getOwnerName());
                    carDto.setOwnerMobile(o.getOwnerMobile());
                    carDto.setCreateTime(currentDate);
                    return carDto;
                }).collect(Collectors.toList());
                carService.saveBatch(carDtos);
            }

            // 获取设备
            List<SimulationDevice> syncDevices = parkingGateClient.getParkingGates();
            List<DeviceDto> deviceDtos = syncDevices.parallelStream()
                    .filter(o -> deviceService.selectByUniqueId(o.getUniqueId(), application.getTenantId()) == null)
                    .map(o -> {
                        DeviceDto deviceDto = new DeviceDto();
                        deviceDto.setUniqueId(o.getUniqueId());
                        deviceDto.setImei(o.getImei());
                        deviceDto.setName(o.getName());
                        deviceDto.setLatitude(o.getLatitude());
                        deviceDto.setLongitude(o.getLongitude());
                        deviceDto.setCreateTime(currentDate);
                        fill(deviceDto, application);
                        return deviceDto;
                    }).collect(Collectors.toList());

            deviceService.saveBatch(deviceDtos);
            return true;
        } catch (Exception e) {
            log.error("模拟平台 道闸同步 syncOrRegisterDevices 异常", e);
        }
        return false;
    }

    @Override
    public boolean subscribeEvents(ApplicationDto application) {
        ApplicationAccessConf.TemplateOfSimulationConf conf = ApplicationAccessConf
                .parseExtStr(ApplicationAccessConf.TemplateOfSimulationConf.class, application.getAccessConf());
        SysTenantDto sysTenantDto = sysTenantService.selectById(application.getTenantId());

        try {
            Preconditions.checkNotNull(conf);
            ParkingGateClient parkingGateClient = SimulationClientBuilder.builder()
                    .url(conf.getUrl())
                    .accessKey(conf.getAccessKey())
                    .accessSecret(conf.getAccessSecret())
                    .build(ParkingGateClient.class);

            String innerBaseUrl = sysConfigService.getConfigValueByKey(SysConfigKeyConstants.GATEWAY_INNER_BASE_URL);
            if (StringUtils.isBlank(innerBaseUrl)) {
                log.warn("Parking gate auth car error, gatewayOuterBaseUrl config is blank.");
                return Boolean.FALSE;
            }
            Response<Object> sub = parkingGateClient.sub(SimulationConstants.EventEnum.PARKING_GATE_ACCESS.getEventCode()
                    , String.format("%s%ssimulation/eventRcv/parkingGateAccess/%s", innerBaseUrl
                            , SystemConstants.ApiPath.COLLECT_PATH.getPath(), sysTenantDto.getCode()));
            if (sub.isSuccess()) {
                return Boolean.TRUE;
            }
        } catch (Exception e) {
            log.error("模拟平台 事件订阅 subscribeEvents 异常", e);
        }
        return Boolean.FALSE;
    }

    @Override
    public boolean sendCmd(DeviceDto deviceDto, DeviceCommandTemplateDto deviceCommandTemplateDto, Map<String, Object> params, Long cmdId) {
        return false;
    }
}
